#ifndef __SUNIV_CLOCK_H__
#define __SUNIV_CLOCK_H__

#include "suniv.h"
#include <types.h>
#include <io.h>


#ifdef __cplusplus
extern "C" {
#endif


static inline void sdelay(int loops)
{
    __asm__ __volatile__("1:\n"
                         "subs %0, %1, #1\n"
                         "bne 1b"
                         : "=r"(loops)
                         : "0"(loops));
}


static inline void clock_pll_enable(int pll)
{
    write32(CCU_BASE + pll, (read32(CCU_BASE + pll) | (1 << 31)));
}


static inline void clock_pll_disable(int pll)
{
    write32(CCU_BASE + pll, (read32(CCU_BASE + pll) & ~(1 << 31)));
}


static inline bool clock_pll_is_ready(int pll)
{
    uint32_t val = read32(CCU_BASE + pll);
    return ((val >> 28) & 0x1) ? true : false;
}


/**
 * @brief set CPU clock source
 * @param clk_src CPU clock source, can be one of:
 *                   0 - CLK_CPU_SRC_LOSC
 *                   1 - CLK_CPU_SRC_OSC24M
 *                   2 - CLK_CPU_SRC_PLL_CPU
 * @return none
 */
void clock_cpu_config(int clk_src);


/**
 * @brief set HCLK clock divider
 * @param div HCLK clock divider, can be one of:
 *              1 - CLK_HCLK_DIV_1
 *              2 - CLK_HCLK_DIV_2
 *              3 - CLK_HCLK_DIV_4
 *              4 - CLK_HCLK_DIV_8
 * @return none
 */
void clock_hclk_config(uint8_t div);


/**
 * @brief set AHB clock source and divider
 * @param clk_src AHB clock source, can be one of:
 *                  0 - CLK_AHB_SRC_LOSC
 *                  1 - CLK_AHB_SRC_OSC24M
 *                  2 - CLK_AHB_SRC_CPUCLK
 *                  3 - CLK_AHB_SRC_PLL_PERIPH_PREDIV
 * 
 * @param pre_div AHB clock pre-divider, can be 1, 2, 3, 4
 * @param div AHB clock divider, can be 1, 2, 4, 8
 * @return none
 */
void clock_ahb_config(int clk_src, uint8_t pre_div, uint8_t div);


/**
 * @brief get APB clock frequency
 * @param div: APB clock divider, can be one of:
 *              1 - CLK_APB_DIV_2
 *              2 - CLK_APB_DIV_4
 *              3 - CLK_APB_DIV_8
 *               
 * return none
 */
void clock_apb_config(int div);


/**
 * @brief initialize CPU PLL
 * @param mul: PLL multiplication factor, can be 1..128
 * @param div: PLL division factor, can be 1..16
 * @return none
 */
void pll_cpu_init(uint8_t mul, uint8_t div);


/**
 * @brief initialize peripheral PLL
 * @param mul: PLL multiplication factor, can be 1..128
 * @param div: PLL division factor, can be 1..16
 * @return none
 */
void pll_periph_init(uint8_t mul, uint8_t div);



#ifdef __cplusplus
}
#endif


#endif // __SUNIV_CLOCK_H__
